package jprint.base.label;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import jprint.base.AppContext;
import jprint.base.util.Strings;

/**
 * @author zw-zheng
 * Created on 2020-12-18
 */
public class LabelPage extends JPanel implements Printable {

    private static final Pattern sCodePattern = Pattern.compile("(\\d+)");
    private int width = 520;
    private int height = 336;

    private final Label label;
    private final AppContext context;
    private int from;
    private int count;
    private BufferedImage image;

    public LabelPage(Label label, AppContext context) {
        this.label = label;
        this.context = context;
    }

    public LabelPage(Label label, AppContext context, int start, int count) {
        this.label = label;
        this.context = context;
        this.from = start;
        this.count = count;
    }

    @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);
        g.drawImage(getImage(), 0, 0, width, height, null);
    }

    public BufferedImage getImage() {
        if (image == null) {
            image = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_565_RGB);
            Graphics2D g2d = image.createGraphics();
            // ---------- 增加下面的代码使得背景透明 -----------------
            image = g2d.getDeviceConfiguration()
                .createCompatibleImage(width, height, Transparency.TRANSLUCENT);
            g2d.dispose();
            g2d = image.createGraphics();
            onDraw(g2d, false, 0);
        }
        return image;
    }

    public byte[] getPngBytes() {
        BufferedImage image = getImage();
        ByteArrayOutputStream out = new ByteArrayOutputStream(4 * 1024);
        try {
            ImageIO.write(image, "png", out);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return out.toByteArray();
    }

    @Override public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
        throws PrinterException {
        Graphics2D g2d = (Graphics2D) graphics;
        if (pageIndex <= count - 1) {
            if ("sun.print.PeekGraphics".equals(graphics.getClass().getCanonicalName())) {
                //java uses class only to query if a page needs printed - save memory/time by short circuiting
                return PAGE_EXISTS;
            }
            // Draw your page as you like...
            // System.out.println("print on graphics: " + pageIndex + "/" + count);
            onDraw(g2d, true, pageIndex);
            // g2d.drawImage(getImage(), 0, 0, null);
            // End of Page
            return PAGE_EXISTS;
        } else {
            return NO_SUCH_PAGE;
        }
    }

    private void onDraw(Graphics2D g2d, boolean forPrint, int pageIndex) {
        //消除文字锯齿
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                             RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        //消除画图锯齿
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // g2d.setColor(Color.WHITE);
        // g2d.fillRect(0, 0, WIDTH, HEIGHT);
        if (forPrint && context.getScale() != 1) {
            g2d.scale(context.getScale(), context.getScale()); // scale test
        }
        // g2d.rotate(Math.PI, width / 2.0, height / 2.0); // 以中心点为圆心旋转180度
        g2d.setColor(Color.BLACK);
        // g2d.drawString(
        //     label.getName()
        //         + width
        //         + " x "
        //         + height
        //         + ", scale="
        //         + context.getScale(), 16, 16);
        // g2d.setStroke(new BasicStroke(2.0f));
        // g2d.drawRect(0, 0, width - 2, height - 2);
        int offsetX = context.getOffset().x;
        int offsetY = context.getOffset().y;
        for (LabelItem item : label.getItems()) {
            int x = item.getLeft();
            int y = item.getTop();
            switch (item.getType()) {
                case "text":
                case "code":
                    g2d.setColor(Color.BLACK);
                    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                                         RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                    float fontSize = 4 * (item.getFontSize() + 0.25f) / 3;
                    Font font =
                        new Font(item.getFontName(),
                                 item.isFontBold() ? Font.BOLD : Font.PLAIN,
                                 Math.round(fontSize));
                    g2d.setFont(font);
                    // 测量字体的ascent, 私有api不建议使用
                    // FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
                    g2d.drawString(makeTextOrCode(item, pageIndex),
                                   offsetX + x,
                                   offsetY + y + item.getHeight() * 3 / 4);
                    break;
                case "image":
                    g2d.drawImage(loadImage(item.getImageSrc()), offsetX + x, offsetY + y,
                                  item.getWidth(),
                                  item.getHeight(), Color.WHITE, null);
                    break;
            }
        }
    }

    private String makeTextOrCode(LabelItem item, int pageIndex) {
        String text = item.getValue();
        if ("code".equals(item.getType())) {
            int code = from + pageIndex;
            if (Strings.isNotVisible(text)) {
                text = String.valueOf(code);
            } else {
                Matcher matcher = sCodePattern.matcher(text);
                if (matcher.find()) {
                    String numbers = matcher.group();
                    int index = text.indexOf(numbers);
                    if (index == 0) {
                        text = String.format("%0" + numbers.length() + "d%s", code,
                                             text.substring(numbers.length()));
                    } else {
                        text =
                            String.format("%s%0" + numbers.length() + "d", text.substring(0, index),
                                          code);
                    }
                } else {
                    text += code;
                }
            }
        }
        return text;
    }

    private BufferedImage loadImage(String name) {
        BufferedImage image = null;
        try {
            image = ImageIO.read(new File(context.getWebRoot(), name));
        } catch (IOException ignored) {
            // ignored
        }
        return image;
    }
}
